#include <sys_config.h>
#include <types.h>
#include <basic_types.h>
#include <mediatypes.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <hld/hld_dev.h>
#include <hld/dmx/dmx.h>

UINT32 g_pvr_pmt_count;
INT32 pvr_pmt_callback(UINT8 *section, INT32 length, UINT32 param)
{
	if (++g_pvr_pmt_count == 1)
	{
#ifdef _DEBUG_PATCH
		libc_printf("patch -> %s send pmt msg - tick %d\n",__FUNCTION__,osal_get_tick());
#endif
		//ap_send_msg(CTRL_MSG_SUBTYPE_CMD_PMT_UPDATE, monitor_id, FALSE);
	}
}

#if 0//def DYNAMIC_PID_SUPPORT
#include <api/libsi/sie_monitor.h>
#include <api/libsi/si_module.h>

#include "win_com.h"
#include "si_monitor_ap.h"

static sim_information g_sim_info[MAX_SIM_CALLBACK_SUPPORT];
static sim_information *g_active_sim_info = NULL;

void api_set_active_sim_info( sim_information * info)
{
    g_active_sim_info = info;
}

sim_information * api_get_active_sim_info(void)
{
    return g_active_sim_info;
}


sim_information* api_get_sim_info_slot_by_prog( UINT8 dmx_id,UINT32 prog_id)
{
    int i = 0;
    for(i = 0;i < MAX_SIM_CALLBACK_SUPPORT; ++i)
    {
        if( (prog_id == g_sim_info[i].prog_id) && (dmx_id == g_sim_info[i].dmx_id) && (NULL != g_sim_info[i].sim_callback))
        {
            return &g_sim_info[i];
        }
    }
    return NULL;
}

sim_information* api_get_sim_info_slot_by_sim( UINT8 dmx_id,UINT32 sim_id)
{
    int i = 0;
    for(i = 0;i < MAX_SIM_CALLBACK_SUPPORT; ++i)
    {
        if( (sim_id == g_sim_info[i].sim_id) && (dmx_id == g_sim_info[i].dmx_id) && (NULL != g_sim_info[i].sim_callback))
        {
            return &g_sim_info[i];
        }
    }
    return NULL;
}


sim_information* api_get_empty_sim_info_slot(void)
{
    int i = 0;
    for(i = 0;i < MAX_SIM_CALLBACK_SUPPORT; ++i)
    {
        if( (0 == g_sim_info[i].sim_id) && (0 == g_sim_info[i].prog_id) && (0 == g_sim_info[i].dmx_id) && ( g_sim_info[i].sim_callback == NULL))
        {
            return &g_sim_info[i];
        }
    }
    return NULL;
}

void api_release_sim_info_slot( sim_information * sim_info)
{
    sim_info->dmx_id = 0;
    sim_info->prog_id = 0;
    sim_info->sim_id = 0;
    sim_info->sim_callback = NULL;
}

void api_set_sim_info_slot(UINT32 sim_id,UINT32 prog_id,UINT8 dmx_id, sim_notify_callback sim_callback,sim_information * sim_info)
{
    sim_info->dmx_id= dmx_id;
    sim_info->prog_id = prog_id;
    sim_info->sim_id = sim_id;
    sim_info->sim_callback = sim_callback;
}

/*
*	name: 	api_sim_start
*	in	:	dmx,sim_type,tp_id,prog_id,sim_calback
*	out	:	sim_id (of what you want to be registered)
*	function:	Monitor a PID of a Table by sim
*/
#define INVALID_SIM_ID (UINT32)(~0)
UINT32 api_sim_start(UINT8 dmx_id, enum MONITE_TB sim_type, UINT32 tp_id, UINT32 prog_id, UINT32 prog_number, UINT16 sim_pid, sim_notify_callback sim_callback)
{
		
	UINT32 ret = INVALID_SIM_ID;
	UINT8 i;
    sim_information* info = NULL;
    struct dmx_device* dmx = (struct dmx_device *)dev_get_by_id(HLD_DEV_TYPE_DMX, dmx_id);

    if(api_get_sim_info_slot_by_prog(dmx_id, prog_id) != NULL)
    {
        return ret;
    }
	sie_open_dmx(dmx, PSI_MODULE_CONCURRENT_FILTER, NULL, 0);
    
	ret = sim_start_monitor(dmx, sim_type, sim_pid, prog_number);
	if(ret != INVALID_SIM_ID)
	{
		//check whether existed monitor
	
		if(sim_callback != NULL)
		{
			if(SUCCESS != sim_register_ncb(ret, sim_callback))
			{
				libc_printf("FAIL!! register callback at sim %d\n", ret);
			}
		}		
        info = api_get_empty_sim_info_slot();
        if(info)
        {
            api_set_sim_info_slot(ret, prog_id, dmx_id, sim_callback, info);
        }        
       // libc_printf("dmx %d %s start sie monitor type[%d] %d: channel_id %d, sim_pid %d\n", dmx_id,((ret == INVALID_SIM_ID) ? "FAIL" : "Success"),  sim_type, ret, prog_id, sim_pid);
        
	}
	return ret;
}

void	api_sim_stop(UINT8 dmx_id, UINT32 prog_id)
{
    sim_information* info = api_get_sim_info_slot_by_prog(dmx_id, prog_id);

    //libc_printf("dmx %d prog_id = %d will be unregister callback %x\n", dmx_id,prog_id,(UINT32)info);
    if(info != NULL)
    {
        //libc_printf("unregister callback at sim %d\n", info->sim_id);
        if(SUCCESS != sim_unregister_ncb(info->sim_id, info->sim_callback))
		{
			;//libc_printf("FAIL!! unregister callback at sim %d\n", info->sim_id);
		}
    	sim_stop_monitor(info->sim_id );        
        api_release_sim_info_slot(info);
    }
	return;
}

/*
*	name:	api_sim_callback
*	in	:	param( Struct sim_cb_param )
*	out	:	SUCCESS or ERR_FAILUE
*	function:	to be registered in sim,  send info "CTRL_MSG_SUBTYPE_CMD_PIDCHANGE" at runtime when the PID monitored changed
*/
INT32 api_sim_callback(UINT32 param)
{
	struct sim_cb_param *sim_param = (struct sim_cb_param *)param;

    INT32 ret = ERR_FAILUE;
	UINT16 sim_pcr_pid;
	UINT16 sim_video_pid;
	UINT16 sim_audio_pid[P_MAX_AUDIO_NUM];
	UINT16 sim_audio_count = P_MAX_AUDIO_NUM;
	static BOOL on_process = FALSE;
    /*
    while(on_process)
    {
        osal_task_sleep(10);
    }
    */
    on_process = TRUE;

	//static var to minitor the ecm and emm pids
	static UINT16 ecm_pids[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};	
	static UINT16 emm_pids[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    static UINT16 ecm_pids_len = 0;
	UINT16 sie_ecm_pids[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
	UINT16 sie_emm_pids[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};	
	UINT8 max_ecm_cnt = 16;
	UINT8 max_emm_cnt = 16;

	static P_NODE p_node; // Come from get_prog_by_id
	INT8 sim_idx = -1, i;

    sim_information* info = api_get_sim_info_slot_by_sim(sim_param->dmx_idx, sim_param->sim_id);
    do{
        if( NULL == info)
        {
            break;
        }
    	if (sim_param->table == MONITE_TB_PMT)
    	{
    		
    		sim_video_pid = sim_pcr_pid = 8191;
    		MEMSET(sim_audio_pid, 8191, P_MAX_AUDIO_NUM);
    		
    		if (ERR_FAILUE == sim_get_video_pid(sim_param->sim_id, &sim_video_pid))
    			break;
    		//sim_get_pmt(sim_param->sim_id, &sim_p_info);
    		if (ERR_FAILUE == sim_get_audio_info(sim_param->sim_id, sim_audio_pid, NULL, &sim_audio_count))	
    			break;
    		if (ERR_FAILUE== sim_get_pcr_pid(sim_param->sim_id, &sim_pcr_pid))
    			break;
            
    		if (ERR_FAILUE == sim_get_ecm_pid(sim_param->sim_id,sie_ecm_pids,&max_ecm_cnt))
    			break;
            
            if ((max_ecm_cnt != 0)
    			&& (MEMCMP(ecm_pids,sie_ecm_pids, sizeof(UINT16)*max_ecm_cnt)!=0))
    		{
                ecm_pids_len = max_ecm_cnt;
                libc_printf("ecms changed max_ecm_cnt:%d\n",max_ecm_cnt);
                MEMCPY(ecm_pids,sie_ecm_pids, sizeof(UINT16)*max_ecm_cnt);
            }else if(ecm_pids_len !=0 && max_ecm_cnt != ecm_pids_len )
            {
                MEMCPY(ecm_pids,sie_ecm_pids, sizeof(UINT16)*(ecm_pids_len>max_ecm_cnt?ecm_pids_len:max_ecm_cnt));
                ecm_pids_len = max_ecm_cnt;
                libc_printf("ecms changed 2 max_ecm_cnt = %d\n",max_ecm_cnt);
            }
            
    		get_prog_by_id(info->prog_id, &p_node);
            
            if(p_node.pmt_pid != sim_param->sec_pid)
    		{
    			//used for debug!!
    			libc_printf("fatal error!");
               break;
    		}
    		
    		//normal mode to update video pid, audio pid, ... except ecm pid & emm pid
            
            //libc_printf("dxm%d sim %d :channel %d pid [v %d, a %d, pcr %d] -> [v %d, a %d, pcr %d]\n", \
            //                    sim_param->dmx_idx,sim_param->sim_id,info->prog_id, p_node.video_pid, p_node.audio_pid[0], p_node.pcr_pid, sim_video_pid, sim_audio_pid[0], sim_pcr_pid);
    		if((sim_video_pid != p_node.video_pid) 
    			|| (sim_pcr_pid != p_node.pcr_pid) 
    			||(sim_audio_count != p_node.audio_count) 
    			||(MEMCMP(p_node.audio_pid,sim_audio_pid, sizeof(UINT16)*sim_audio_count)!=0))
    		{
    			if ((PROG_TV_MODE ==p_node.av_flag)
    				&&((0 == sim_video_pid) ||(8191 == sim_video_pid)
    				     ||(0 == sim_pcr_pid) ||(8191 == sim_pcr_pid)
    				     ||(0 == sim_audio_pid[0]) ||(8191 == sim_audio_pid[0])))
    				break;
    			if ((PROG_RADIO_MODE ==p_node.av_flag)
    				&&((0 != sim_video_pid) ||(8191 != sim_video_pid)
    				     ||(0 == sim_pcr_pid) ||(8191 == sim_pcr_pid)
    				     ||(0 == sim_audio_pid[0]) ||(8191 == sim_audio_pid[0])))
    				break;	
    			//libc_printf("dxm%d sim %d :channel %d pid changed![v %d, a %d, pcr %d] -> [v %d, a %d, pcr %d]\n", \
    			//	sim_param->dmx_idx,sim_param->sim_id,info->prog_id, p_node.video_pid, p_node.audio_pid[0], p_node.pcr_pid, sim_video_pid, sim_audio_pid[0], sim_pcr_pid);
    			if(PROG_TV_MODE ==p_node.av_flag)
    				 p_node.video_pid = sim_video_pid;			
    			p_node.pcr_pid = sim_pcr_pid;
			
				p_node.audio_count = sim_audio_count;
				MEMCPY(p_node.audio_pid, sim_audio_pid, sizeof(UINT16)*sim_audio_count);
    			
    			modify_prog(p_node.prog_id, &p_node);
                update_data();
                api_set_active_sim_info(info);
    			ap_send_msg(CTRL_MSG_SUBTYPE_CMD_PIDCHANGE, p_node.prog_id, FALSE);//move down for sending MSG after modifed p_node
    		}
    	}

    		//CA mode to update emm pid  pid
    	if ( sim_param->table == MONITE_TB_CAT )
    	{
    		if (ERR_FAILUE == sim_get_emm_pid(sim_param->sim_id,sie_emm_pids,&max_emm_cnt))
    			break;
    		if ((p_node.ca_mode) 
    			&&(max_emm_cnt != 0)
    			&& (MEMCMP(emm_pids,sie_ecm_pids, sizeof(UINT16)*max_emm_cnt)!=0))
    		{
    			for (i=0;i<max_emm_cnt;i++)
    			{
    				libc_printf("emm pid changed![ %d] -> [ %d]\n",emm_pids[i],sie_emm_pids[i]);
    			}
    			libc_printf("Dynamic PID cause EMM changed!\n Need to update code to support it\n");
    			MEMCPY(emm_pids,sie_emm_pids, sizeof(UINT16)*max_emm_cnt);
    			// TO DO:  add ca interface to change the ecm_pids and emm_pids
    			// TO DO:  add pvr  interface to change the ecm_pids and emm_pids
    		}
    	}
        ret = SUCCESS;       
    }while(0);
    on_process = FALSE;
    
	return ret;
}
#endif



